﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Media;
using System.Windows.Ink;
using System.Windows.Controls;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Ionic.Zip;

namespace MediaPad.Serialization
{
    [Serializable]
    public class SerializationBaseInfo : ISerializable
    {
        public Uri FilePath
        {
            get;
            set;
        }

        public double CanvasX
        {
            get;
            set;
        }

        public double CanvasY
        {
            get;
            set;
        }

        public Size Size
        {
            get;
            set;
        }

		public double MediaRotationAngle
		{
			get;
			set;
		}

        public SerializationBaseInfo()
        {
 
        }

        protected SerializationBaseInfo(SerializationInfo info, StreamingContext context)
		{
			if ( info == null )
				return;

            FilePath = (Uri)info.GetValue("FilePath", typeof(Uri));
            CanvasX = (double)info.GetValue("CanvasX", typeof(double));
            CanvasY = (double)info.GetValue("CanvasY", typeof(double));
            Size = (Size)info.GetValue("Size", typeof(Size));
			MediaRotationAngle = (double)info.GetValue("MediaRotationAngle", typeof(double));
        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("FilePath", FilePath);
            info.AddValue("CanvasX", CanvasX);
            info.AddValue("CanvasY", CanvasY);
            info.AddValue("Size", Size);
			info.AddValue("MediaRotationAngle", MediaRotationAngle);
        }
    }

    [Serializable]
    public class SerializationTextBoxInfo : SerializationBaseInfo, ISerializable
    {
        public string FontFamilyName
        {
            get;
            set;
        }

        public double FontSize
        {
            get;
            set;
        }

        /// <summary>
        /// Hash code for FontStyle
        /// </summary>
        public int FontStyle
        {
            get;
            set;
        }

        /// <summary>
        /// int value. (for Bold - 700)
        /// </summary>
        public int FontWeight
        {
            get;
            set;
        }

        /// <summary>
		/// Underline = 0, OverLine = 1, Strikethrough = 2, Baseline = 3.
        /// </summary>
        public List<int> TextDecorations
        {
            get;
            set;
        }

		public string Foreground
		{
			get;
			set;
		}

		/// <summary>
		/// Condensed - 3; Expanded - 7; ExtraCondensed - 2; ExtraExpanded - 8;
		/// Medium - 5; Normal - 5; SemiCondensed - 4; SemiExpanded - 6;
		/// UltraCondensed - 1; UltraExpanded - 9;
		/// </summary>
		public int FontStretch
		{
			get;
			set;
		}

        public string Text
        {
            get;
            set;
        }

        public SerializationTextBoxInfo()
        {
        }

        protected SerializationTextBoxInfo(SerializationInfo info, StreamingContext context)
            : base(info, context)
		{
			if ( info == null )
				return;

            FontFamilyName = (string)info.GetValue("FontFamilyName", typeof(string));
            FontSize = (double)info.GetValue("FontSize", typeof(double));
            FontStyle = (int)info.GetValue("FontStyle", typeof(int));
            FontWeight = (int)info.GetValue("FontWeight", typeof(int));
            TextDecorations = (List<int>)info.GetValue("TextDecorations", typeof(List<int>));
			Foreground = (string)info.GetValue("Foreground", typeof(string));
			FontStretch = (int)info.GetValue("FontStretch", typeof(int));
            Text = (string)info.GetValue("Text", typeof(string));
        }

        #region ISerializable Members

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info,context);

            info.AddValue("FontFamilyName", FontFamilyName);
            info.AddValue("FontSize", FontSize);
            info.AddValue("FontStyle", FontStyle);
            info.AddValue("FontWeight", FontWeight);
            info.AddValue("TextDecorations", TextDecorations);
			info.AddValue("Foreground", Foreground);
			info.AddValue("FontStretch", FontStretch);
            info.AddValue("Text", Text);
        }

        #endregion
    }

    [Serializable]
    public class SerializationStrokesInfo : ISerializable
    {
        public byte[] StrokeCollection
        {
            get;
            set;
        }

        public SerializationDrawingAttributesInfo[] SerializationDrawingAttributesInfo
        {
            get;
            set;
        }

        public SerializationStrokesInfo()
        {
        }

        protected SerializationStrokesInfo(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                return;

            StrokeCollection = (byte[])info.GetValue("StrokeCollection", typeof(byte[]));
            SerializationDrawingAttributesInfo = (SerializationDrawingAttributesInfo[])info.GetValue("SerializationDrawingAttributesInfo", typeof(SerializationDrawingAttributesInfo[]));
        }

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                return;

            info.AddValue("StrokeCollection", StrokeCollection);
            info.AddValue("SerializationDrawingAttributesInfo", SerializationDrawingAttributesInfo);
        }

        #endregion
    }

    [Serializable]
    public class SerializationDrawingAttributesInfo : ISerializable
    {
        public byte ColorA { get; set; }
        public byte ColorR { get; set; }
        public byte ColorG { get; set; }
        public byte ColorB { get; set; }
        public double Height { get; set; }
        public double Width { get; set; }
        public bool FitToCurve { get; set; }
        public bool IgnorePressure { get; set; }
        public bool IsHighlighter { get; set; }

        public SerializationDrawingAttributesInfo()
        {
        }

        protected SerializationDrawingAttributesInfo(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                return;

            ColorA = (byte)info.GetValue("ColorA", typeof(byte));
            ColorR = (byte)info.GetValue("ColorR", typeof(byte));
            ColorG = (byte)info.GetValue("ColorG", typeof(byte));
            ColorB = (byte)info.GetValue("ColorB", typeof(byte));
            Height = (double)info.GetValue("Height", typeof(double));
            Width = (double)info.GetValue("Width", typeof(double));
            FitToCurve = (bool)info.GetValue("FitToCurve", typeof(bool));
            IgnorePressure = (bool)info.GetValue("IgnorePressure", typeof(bool));
            IsHighlighter = (bool)info.GetValue("IsHighlighter", typeof(bool));
        }

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                return;

            info.AddValue("ColorA", ColorA);
            info.AddValue("ColorR", ColorR);
            info.AddValue("ColorG", ColorG);
            info.AddValue("ColorB", ColorB);
            info.AddValue("Height", Height);
            info.AddValue("Width", Width);
            info.AddValue("FitToCurve", FitToCurve);
            info.AddValue("IgnorePressure", IgnorePressure);
            info.AddValue("IsHighlighter", IsHighlighter);
        }

        #endregion
    }

    [Serializable]
    public class InkCanvasSerializationInfo : ISerializable
    {
        public SerializationStrokesInfo StrokesInfo
        {
            get;
            set;
        }

        public SerializationBaseInfo[] Images
        {
            get;
            set;
        }

        public SerializationBaseInfo[] MediaElements
        {
            get;
            set;
        }

        public SerializationTextBoxInfo[] TextBoxes
        {
            get;
            set;
        }

        public string Background
        {
            get;
            set;
        }

        public InkCanvasSerializationInfo()
        {
 
        }

        protected InkCanvasSerializationInfo(SerializationInfo info, StreamingContext context)
		{
			if ( info == null )
				return;

            StrokesInfo = (SerializationStrokesInfo)info.GetValue("StrokesInfo", typeof(SerializationStrokesInfo));
            Images = (SerializationBaseInfo[])info.GetValue("Images", typeof(SerializationBaseInfo[]));
            MediaElements = (SerializationBaseInfo[])info.GetValue("MediaElements", typeof(SerializationBaseInfo[]));
            TextBoxes = (SerializationTextBoxInfo[])info.GetValue("TextBoxes", typeof(SerializationTextBoxInfo[]));
            Background = (string)info.GetValue("Background", typeof(string));
        }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("StrokesInfo", StrokesInfo);
            info.AddValue("Images", Images);
            info.AddValue("MediaElements", MediaElements);
            info.AddValue("TextBoxes", TextBoxes);
            info.AddValue("Background", Background);
        }
    }

    public class Serializer
    {
        public static void SerializeObject(string fs, InkCanvasSerializationInfo info, bool deleteFolder, string tempFile)
        {
            string fileName = Path.GetFileNameWithoutExtension(fs);
            string dirName = Directory.GetParent(tempFile).FullName;

            string datFile = dirName + "\\" + fileName + ".dat";
            using (FileStream file = new FileStream(datFile, FileMode.Create, FileAccess.Write))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                try
                {
                    formatter.Serialize(file, info);
                }
                catch (SerializationException e)
                {
                    Console.WriteLine("Failed to serialize. Reason: " + e.Message);
                    throw;
                }
                finally
                {
                    file.Close();
                }
            }

            string directory = Path.GetDirectoryName(datFile) + "\\" + fileName;

            ZipFile zipFile = new ZipFile();
            zipFile.AddFile(datFile, "");
            zipFile.AddDirectory(directory, Path.GetFileNameWithoutExtension(directory));
            zipFile.Save(fs);

            File.Delete(datFile);

            if (deleteFolder)
            {
                Directory.Delete(directory, true);
            }
        }

        public static InkCanvasSerializationInfo DeSerializeObject(string fileName)
        {
            InkCanvasSerializationInfo info = new InkCanvasSerializationInfo();

            using (FileStream file = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                try
                {
                    info = (InkCanvasSerializationInfo)formatter.Deserialize(file);
                }
                catch (SerializationException e)
                {
                    Console.WriteLine("Failed to write. Reason: " + e.Message);
                    throw;
                }
                finally
                {
                    file.Close();
                }
            }

            return info;
        }
    }
}
